package parse_and_index.pdf;

/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
//package org.apache.pdfbox;

import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.io.Writer;
import java.net.MalformedURLException;
import java.net.URL;

import org.apache.pdfbox.exceptions.CryptographyException;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.encryption.AccessPermission;
import org.apache.pdfbox.pdmodel.encryption.BadSecurityHandlerException;
import org.apache.pdfbox.pdmodel.encryption.StandardDecryptionMaterial;
import org.apache.pdfbox.util.PDFText2HTML;
import org.apache.pdfbox.util.PDFTextStripper;
//import java.io.InputStream;
//import java.io.OutputStream;

/**
 * This is the main program that simply parses the pdf document and transforms it into text.
 * 
 * @author <a href="mailto:ben@benlitchfield.com">Ben Litchfield</a>
 * @version $Revision: 1.14 $
 */
public class PDFTextExtractor {
	  private static final String PASSWORD	 = "-password";
	  private static final String ENCODING	 = "-encoding";
	  private static final String CONSOLE	  = "-console";
	  private static final String START_PAGE   = "-startPage";
	  private static final String END_PAGE	 = "-endPage";
	  private static final String SORT		 = "-sort";
	  private static final String IGNORE_BEADS = "-ignoreBeads";
	  private static final String HTML		 = "-html";	   // jjb - added simple HTML output
	  private static final String FORCE		= "-force";	  // enables pdfbox to skip corrupt objects

	  /**
	   * Infamous main method.
	   * 
	   * @param args
	   *              Command line arguments, should be one and a reference to a file.
	   * 
	   * @throws Exception
	   *               If there is an error parsing the document.
	   */
	  public static void extract(final String[] args) throws Exception {
			boolean toConsole = false;
			boolean toHTML = false;
			boolean force = false;
			boolean sort = false;
			boolean separateBeads = true;
			String password = "";
			String encoding = null;
			String pdfFile = null;
			String outputFile = null;
			// Defaults to text files
			String ext = ".txt";
			int startPage = 1;
			int endPage = Integer.MAX_VALUE;
			for (int i = 0; i < args.length; i++) {
				  if (args[i].equals(PASSWORD)) {
						i++;
						if (i >= args.length) {
							  usage();
						}
						password = args[i];
				  }
				  else if (args[i].equals(ENCODING)) {
						i++;
						if (i >= args.length) {
							  usage();
						}
						encoding = args[i];
				  }
				  else if (args[i].equals(START_PAGE)) {
						i++;
						if (i >= args.length) {
							  usage();
						}
						startPage = Integer.parseInt(args[i]);
				  }
				  else if (args[i].equals(HTML)) {
						toHTML = true;
						ext = ".html";
				  }
				  else if (args[i].equals(SORT)) {
						sort = true;
				  }
				  else if (args[i].equals(IGNORE_BEADS)) {
						separateBeads = false;
				  }
				  else if (args[i].equals(END_PAGE)) {
						i++;
						if (i >= args.length) {
							  usage();
						}
						endPage = Integer.parseInt(args[i]);
				  }
				  else if (args[i].equals(CONSOLE)) {
						toConsole = true;
				  }
				  else if (args[i].equals(FORCE)) {
						force = true;
				  }
				  else {
						if (pdfFile == null) {
							  pdfFile = args[i];
						}
						else {
							  outputFile = args[i];
						}
				  }
			}

			if (pdfFile == null) {
				  usage();
			}
			else {
				  if ((encoding == null) && (toHTML)) {
						encoding = "UTF-8";
				  }
				  outputFile = getOutputFile(toConsole, toHTML, force, sort, separateBeads, password, encoding, pdfFile, outputFile, ext, startPage, endPage);
			}
			if (!toHTML) {
				  extractToPlainText(encoding, outputFile);
			}
	  }

	  public static String getOutputFile(final String pdfFile, final String encoding) throws UnsupportedEncodingException, FileNotFoundException, IOException, BadSecurityHandlerException, CryptographyException {
			return PDFTextExtractor.getOutputFile(false, false, false, false, true, "", encoding, pdfFile, null, ".txt", 1, Integer.MAX_VALUE);
	  }

	  public static String getOutputFile(final boolean toConsole, final boolean toHTML, final boolean force, final boolean sort, final boolean separateBeads, final String password, final String encoding, final String pdfFile, String outputFile, final String ext, final int startPage, int endPage) throws IOException, BadSecurityHandlerException, CryptographyException, UnsupportedEncodingException,
				  FileNotFoundException {
			Writer output = null;
			PDDocument document = null;
			try {
				  try {
						// basically try to load it from a url first and if the URL is not recognized then try to load it from the file system.
						final URL url = new URL(pdfFile);
						document = PDDocument.load(url, force);
						final String fileName = url.getFile();
						if ((outputFile == null) && (fileName.length() > 4)) {
							  outputFile = new File(fileName.substring(0, fileName.length() - 4) + ext).getName();
						}
				  }
				  catch (final MalformedURLException e) {
						document = PDDocument.load(pdfFile, force);
						if ((outputFile == null) && (pdfFile.length() > 4)) {
							  outputFile = pdfFile.substring(0, pdfFile.length() - 4) + ext;
						}
				  }

				  // document.print();
				  if (document.isEncrypted()) {
						final StandardDecryptionMaterial sdm = new StandardDecryptionMaterial(password);
						document.openProtection(sdm);
						final AccessPermission ap = document.getCurrentAccessPermission();

						if (!ap.canExtractContent()) { throw new IOException("You do not have permission to extract text"); }
				  }

				  if (toConsole) {
						output = new OutputStreamWriter(System.out);
				  }
				  else {
						if (encoding != null) {
							  output = new OutputStreamWriter(new FileOutputStream(outputFile), encoding);
						}
						else {
							  // use default encoding
							  output = new OutputStreamWriter(new FileOutputStream(outputFile));
						}
				  }

				  PDFTextStripper stripper = null;
				  if (toHTML) {
						stripper = new PDFText2HTML(encoding);
				  }
				  else {
						stripper = new PDFTextStripper(encoding);
				  }
				  stripper.setForceParsing(force);
				  stripper.setSortByPosition(sort);
				  stripper.setShouldSeparateByBeads(separateBeads);
				  if (!toHTML) {
						if (endPage == Integer.MAX_VALUE) {
							  endPage = 2000;
						}
						stripper.getEndPage();
						// System.out.println(endPage);
						for (int i = startPage; i < endPage; i++) {
							  stripper.setStartPage(i);
							  stripper.setEndPage(i);
							  output.append("\n !PAGESEPARATOR! \n");
							  stripper.writeText(document, output);
						}
				  }
				  else {
						stripper.writeText(document, output);
				  }

			}
			finally {
				  if (output != null) {
						output.close();
				  }
				  if (document != null) {
						document.close();
				  }
			}
			return outputFile;
	  }

	  public static void extractToPlainText(final String encoding, final String outputFile) throws FileNotFoundException, UnsupportedEncodingException, IOException {
			FileInputStream fstream = new FileInputStream(outputFile);
			DataInputStream in = new DataInputStream(fstream);
			System.out.println(encoding);
			BufferedReader br = new BufferedReader(new InputStreamReader(in, encoding));

			String strLine = "";
			int sepNum = 0;
			final String outputFileTmp = outputFile + ".tmp";

			final OutputStreamWriter outputTmp = new OutputStreamWriter(new FileOutputStream(outputFileTmp), encoding);

			while ((strLine = br.readLine()) != null) {
				  final String[] temp = strLine.split(" ");
				  for (int i = 0; i < temp.length; i++) {
						temp[i].trim();
						if (temp[i].equalsIgnoreCase("!PAGESEPARATOR!") || temp[i].equalsIgnoreCase("</body></html>")) {
							  sepNum++;
							  if (sepNum > 4) {
									break;
							  }
							  else {
									continue;
							  }
						}
						else if (!(temp[i].equalsIgnoreCase(""))) {
							  sepNum = 0;
						}
				  }
				  if (sepNum > 2) {
						break;
				  }
				  else {
						outputTmp.append(strLine + "\n");
				  }
			}

			br.close();
			in.close();
			fstream.close();
			outputTmp.close();

			fstream = new FileInputStream(outputFileTmp);
			in = new DataInputStream(fstream);
			br = new BufferedReader(new InputStreamReader(in, encoding));

			strLine = "";

			final OutputStreamWriter output = new OutputStreamWriter(new FileOutputStream(outputFile), encoding);

			while ((strLine = br.readLine()) != null) {
				  output.append(strLine + "\n");
			}

			br.close();
			in.close();
			fstream.close();
			output.close();

			final File src = new File(outputFileTmp);
			src.delete();
	  }

	  /**
	   * This will print the usage requirements and exit.
	   */
	  private static void usage() {
			System.err.println("Usage: java org.apache.pdfbox.ExtractText [OPTIONS] <PDF file> [Text File]\n" + "  -password  <password>        Password to decrypt document\n" + "  -encoding  <output encoding> (ISO-8859-1,UTF-16BE,UTF-16LE,...)\n" + "  -console                     Send text to console instead of file\n"
						+ "  -html                        Output in HTML format instead of raw text\n" + "  -sort                        Sort the text before writing\n" + "  -ignoreBeads                 Disables the separation by beads\n" + "  -force                       Enables pdfbox to ignore corrupt objects\n" + "  -startPage <number>          The first page to start extraction(1 based)\n"
						+ "  -endPage <number>            The last page to extract(inclusive)\n" + "  <PDF file>                   The PDF document to use\n" + "  [Text File]                  The file to write the text to\n");
			System.exit(1);
	  }
}